import re
import requests
from typing import Optional, Dict, Any
from datetime import datetime
from flask import current_app


def validate_wechat_code(code: str) -> Optional[str]:
    """
    验证微信小程序授权码，返回openid
    """
    if not code:
        return None
    
    try:
        # 微信小程序配置
        app_id = current_app.config.get('WECHAT_APP_ID')
        app_secret = current_app.config.get('WECHAT_APP_SECRET')
        
        if not app_id or not app_secret:
            current_app.logger.error('微信小程序配置缺失')
            return None
        
        # 调用微信API获取session_key和openid
        url = 'https://api.weixin.qq.com/sns/jscode2session'
        params = {
            'appid': app_id,
            'secret': app_secret,
            'js_code': code,
            'grant_type': 'authorization_code'
        }
        
        response = requests.get(url, params=params, timeout=10)
        data = response.json()
        
        if 'errcode' in data:
            current_app.logger.error(f'微信API错误: {data}')
            return None
        
        return data.get('openid')
        
    except Exception as e:
        current_app.logger.error(f'微信授权验证失败: {str(e)}')
        return None


def validate_phone(phone: str) -> bool:
    """
    验证手机号格式
    """
    if not phone:
        return False
    
    # 中国大陆手机号正则
    pattern = r'^1[3-9]\d{9}$'
    return bool(re.match(pattern, phone))


def validate_treatment_params(params: Dict[str, Any]) -> Optional[str]:
    """
    验证治疗参数
    """
    if not isinstance(params, dict):
        return "参数必须是字典格式"
    
    # 验证治疗模式
    treatment_mode = params.get('treatment_mode')
    if not treatment_mode:
        return "缺少治疗模式参数"
    
    valid_modes = ['tDCS+', 'tDCS-', 'tACS']
    if treatment_mode not in valid_modes:
        return f"无效的治疗模式，支持的模式: {', '.join(valid_modes)}"
    
    # 验证电流强度
    current_intensity = params.get('current_intensity')
    if current_intensity is not None:
        try:
            intensity = float(current_intensity)
            if not 0.01 <= intensity <= 2.0:  # 修改为0.01-2.0范围
                return "电流强度必须在0.01-2.0mA范围内"
            
        except (ValueError, TypeError):
            return "电流强度必须是有效数字"
    
    # 验证治疗时间
    treatment_duration = params.get('treatment_duration')
    if treatment_duration is not None:
        try:
            duration = int(treatment_duration)
            valid_durations = [10, 15, 20, 30]
            if duration not in valid_durations:
                return f"治疗时间必须是以下值之一: {', '.join(map(str, valid_durations))}分钟"
        except (ValueError, TypeError):
            return "治疗时间必须是整数"
    
    # 验证频率（仅tACS模式需要）
    if treatment_mode == 'tACS':
        frequency = params.get('frequency')
        if frequency is None:
            return "tACS模式必须设置频率参数"
        
        try:
            freq = float(frequency)
            if not 0.1 <= freq <= 100.0:
                return "频率必须在0.1-100Hz范围内"
        except (ValueError, TypeError):
            return "频率必须是有效数字"
    
    # 验证时间参数
    start_time = params.get('start_time')
    if start_time:
        try:
            datetime.fromisoformat(start_time.replace('Z', '+00:00'))
        except ValueError:
            return "开始时间格式无效，请使用ISO格式"
    
    end_time = params.get('end_time')
    if end_time:
        try:
            datetime.fromisoformat(end_time.replace('Z', '+00:00'))
        except ValueError:
            return "结束时间格式无效，请使用ISO格式"
    
    # 验证效果评分
    effectiveness_score = params.get('effectiveness_score')
    if effectiveness_score is not None:
        try:
            score = int(effectiveness_score)
            if not 1 <= score <= 10:
                return "效果评分必须在1-10范围内"
        except (ValueError, TypeError):
            return "效果评分必须是整数"
    
    # 验证治疗状态
    status = params.get('status')
    if status:
        valid_statuses = ['completed', 'interrupted', 'cancelled']
        if status not in valid_statuses:
            return f"无效的治疗状态，支持的状态: {', '.join(valid_statuses)}"
    
    return None  # 验证通过


def validate_device_id(device_id: str) -> bool:
    """
    验证设备ID格式
    """
    if not device_id:
        return False
    
    # 设备ID格式：MDK_001_XXXXXX（MDK_001前缀 + 6位数字或字母）
    pattern = r'^MDK_001_[A-Z0-9]{6}$'
    return bool(re.match(pattern, device_id))


def validate_template_params(params: Dict[str, Any]) -> Optional[str]:
    """
    验证治疗模板参数
    """
    if not isinstance(params, dict):
        return "参数必须是字典格式"
    
    # 验证模板名称
    template_name = params.get('template_name')
    if not template_name:
        return "缺少模板名称"
    
    if len(template_name.strip()) < 1:
        return "模板名称不能为空"
    
    if len(template_name) > 100:
        return "模板名称长度不能超过100个字符"
    
    # 验证治疗参数（复用治疗参数验证）
    treatment_validation = validate_treatment_params(params)
    if treatment_validation:
        return treatment_validation
    
    return None


def validate_pagination_params(page: Any, limit: Any) -> tuple[int, int, Optional[str]]:
    """
    验证分页参数
    """
    try:
        page_num = int(page) if page else 1
        limit_num = int(limit) if limit else 20
        
        if page_num < 1:
            return 1, limit_num, "页码必须大于0"
        
        if limit_num < 1:
            return page_num, 20, "每页数量必须大于0"
        
        if limit_num > 100:
            return page_num, 100, "每页数量不能超过100"
        
        return page_num, limit_num, None
        
    except (ValueError, TypeError):
        return 1, 20, "分页参数必须是有效数字"


def validate_date_range(start_date: str, end_date: str) -> Optional[str]:
    """
    验证日期范围
    """
    try:
        if start_date:
            start_dt = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
        else:
            start_dt = None
        
        if end_date:
            end_dt = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
        else:
            end_dt = None
        
        if start_dt and end_dt:
            if start_dt > end_dt:
                return "开始日期不能晚于结束日期"
            
            # 检查日期范围不能超过1年
            if (end_dt - start_dt).days > 365:
                return "日期范围不能超过1年"
        
        return None
        
    except ValueError:
        return "日期格式无效，请使用ISO格式"


def validate_search_query(query: str) -> Optional[str]:
    """
    验证搜索查询参数
    """
    if not query:
        return None
    
    # 清理查询字符串
    query = query.strip()
    
    if len(query) < 1:
        return "搜索关键词不能为空"
    
    if len(query) > 100:
        return "搜索关键词长度不能超过100个字符"
    
    # 检查是否包含危险字符
    dangerous_chars = ['<', '>', '"', "'", '&', ';', '(', ')', '|', '`']
    for char in dangerous_chars:
        if char in query:
            return f"搜索关键词不能包含特殊字符: {char}"
    
    return None


def validate_sort_params(sort_field: str, sort_order: str) -> Optional[str]:
    """
    验证排序参数
    """
    if sort_field:
        # 定义允许的排序字段
        allowed_fields = [
            'id', 'created_at', 'updated_at', 'treatment_count',
            'last_login', 'treatment_duration', 'current_intensity',
            'effectiveness_score', 'device_id', 'status'
        ]
        
        if sort_field not in allowed_fields:
            return f"不支持的排序字段: {sort_field}"
    
    if sort_order:
        if sort_order not in ['asc', 'desc']:
            return "排序方向必须是 'asc' 或 'desc'"
    
    return None


def sanitize_input(input_str: str, max_length: int = 255) -> str:
    """
    清理输入字符串
    """
    if not input_str:
        return ""
    
    # 移除首尾空白
    cleaned = input_str.strip()
    
    # 限制长度
    if len(cleaned) > max_length:
        cleaned = cleaned[:max_length]
    
    # 转义HTML特殊字符
    html_escape_table = {
        "&": "&amp;",
        '"': "&quot;",
        "'": "&#x27;",
        ">": "&gt;",
        "<": "&lt;",
    }
    
    for char, escape in html_escape_table.items():
        cleaned = cleaned.replace(char, escape)
    
    return cleaned


def validate_file_upload(file_data: bytes, allowed_types: list, max_size: int = 5 * 1024 * 1024) -> Optional[str]:
    """
    验证文件上传
    """
    if not file_data:
        return "文件数据为空"
    
    if len(file_data) > max_size:
        return f"文件大小不能超过 {max_size // (1024 * 1024)}MB"
    
    # 检查文件类型（通过文件头）
    file_signatures = {
        'jpg': [b'\xff\xd8\xff'],
        'png': [b'\x89\x50\x4e\x47'],
        'gif': [b'\x47\x49\x46\x38'],
        'pdf': [b'\x25\x50\x44\x46'],
        'csv': [b''],  # CSV没有固定的文件头
    }
    
    if allowed_types:
        valid_type = False
        for file_type in allowed_types:
            if file_type in file_signatures:
                signatures = file_signatures[file_type]
                for signature in signatures:
                    if not signature or file_data.startswith(signature):
                        valid_type = True
                        break
                if valid_type:
                    break
        
        if not valid_type:
            return f"不支持的文件类型，允许的类型: {', '.join(allowed_types)}"
    
    return None